#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

#include "common.h"
#include "log4cplus.h"
#include "config.h"
#include "watchdog.h"

static int g_exitProgram = 0;

/**
 * @brief 信号处理，捕获正常退出和异常退出信号
 * @return 
*/
static void sighandler(int sig)
{
    log_info_fmt("input signal [%d]", sig);
    if (sig == SIGTERM || sig == SIGINT)
    {
        g_exitProgram = 1;
    }
    else if (sig == SIGSEGV || sig == SIGABRT)
    {
        log_error_fmt("segment fault, exit...");
        exit(1);
    }
    return;
}

/**
 * @brief 延迟启动，即查询系统启动到当前的间隔时间，如果小于预期，则延迟等待
 * @return 
*/
static void delayWait(int delayTime)
{
    time_t t;
    long uptime;

    while (!g_exitProgram)
    {
        time(&t);
        uptime = getSystemUptime();
        if (uptime >= (long)delayTime) {
            log_info_fmt("delay wait complete, delayTime=[%d]", delayTime);
            break;
        }

        log_debug_fmt("sys uptime=[%ld], delayTime=[%d]", uptime, delayTime);
        sleep(10);
    }
}

int main()
{
    int delayTime;
    int rebootTime;
    int feedTime;
    int lastFeedTime = 0;
    std::string hardware;
    struct sigaction act;
    int iRet;

    // 后台执行
    daemonInit();
    if (alreadyRunning())
    {
        printf("already running...\n");
        return 1;
    }

    // 日志初始化
    log4cplush_init();

    // 自定义信号处理初始化
    act.sa_handler = sighandler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_RESTART;
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT, &act, NULL);
    sigaction(SIGSEGV, &act, NULL);
    sigaction(SIGABRT, &act, NULL);

    // 获取配置参数
    delayTime = ConfigParse::GetInstance(WATCH_CONFIG_PATH).GetDelayTime();
    rebootTime = ConfigParse::GetInstance(WATCH_CONFIG_PATH).GetRebootTime();
    feedTime = ConfigParse::GetInstance(WATCH_CONFIG_PATH).GetFeedTime();
    hardware = ConfigParse::GetInstance(WATCH_CONFIG_PATH).GetHardware();

    // 通过配置开关，判断是否启动
    if (ConfigParse::GetInstance(WATCH_CONFIG_PATH).GetStatus() != 1) {
        log_info_fmt("watchdog status is disable, service exit ...");
        return 0;
    }

    // 适配硬件狗
    HARDWARE_TYPE hw = getHardwareType();
    switch (hw)
    {
    case HARDWARE_JH:
        if (wdtLoadLibrary(WDT_JH_PATH) == -1) {
            return 0;
        }
        break;
    case HARDWARE_TYC:
        if (wdtLoadLibrary(WDT_TYC_PATH) == -1) {
            return 0;
        }
        break;
    default:
        log_warn_fmt("The current hardware does not support watchdog, Go to sleep...");
        while (!g_exitProgram) {
             usleep(100000);
        }
        return 0;
    }

    // 延迟启动
    delayWait(delayTime);

    // 加载驱动
    if (wdtLoadDriver() != 0) {
        log_warn_fmt("load watchdog driver failure");
        return 1;
    }

    // 启动硬件狗
    if (wdtStart() != 0) {
        wdtUnloadDriver();
        log_warn_fmt("watchdog start failure, service exit ...");
        return 1;
    }
    log_info_fmt("watchdog start successful");

    // 主循环，持续喂狗
    while (!g_exitProgram)
    {
        // 获取硬件狗倒计时
        iRet = wdtStatus();
        if (iRet != -1) {
            log_debug_fmt("left reboot time [%d] seconds.", iRet);
        } else {
            log_warn_fmt("watchdog dog unexpectedly shut down, restart it");
            wdtStop();
            wdtStart();
        }

        // 喂狗，失败重试一次
        if (wdtFeed(feedTime, rebootTime) != 0) {
            log_warn_fmt("feed dog failure, try again");

            wdtStop();
            wdtUnloadDriver();
            wdtLoadDriver();
            wdtStart();

            if (wdtFeed(feedTime, rebootTime) != 0) {
                log_error_fmt("feed dog failure, ready to exit ...");
                break;
            }
        }

        // 间隔5s
        sleep(5);
    }

    log_info_fmt("watchdog stop ...");
    wdtStop();
    log_info_fmt("watchdog driver unloading ...");
    wdtUnloadDriver();
    log_info_fmt("watchDog service quit ...");
    return 0;
}
